/*
    Copyright 2006-2011 Patrik Jonsson, sunrise@familjenjonsson.org

    This file is part of Sunrise.

    Sunrise is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    Sunrise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Sunrise.  If not, see <http://www.gnu.org/licenses/>.

*/

/// \file
/// Declaration of a grid class used for the non-scattering, full-SED runs.

#ifndef __polychromatic_grid__
#define __polychromatic_grid__

#include "optical.h"
#include "emission.h"
#include "chromatic_policy.h"
#include "mcrx-units.h"

namespace mcrx {
  template<typename> class polychromatic_grid;
  // forward decl
  class density_generator;
}

namespace CCfits {
  class ExtHDU;
}

/** An adaptive_grid for polychromatic runs. To improve locality, it
    keeps the density and intensity vectors of the cells in single
    memory blocks. */
template<typename grid_type>
class mcrx::polychromatic_grid
{
public:
  typedef grid_type T_grid_impl;
  // wtf is this shortcutting to the absorber??
  typedef typename T_grid_impl::T_data::T_absorber T_data;
  typedef typename T_data::T_lambda T_lambda;
  typedef typename T_grid_impl::T_cell T_cell;
  typedef typename T_grid_impl::T_cell_tracker T_cell_tracker;
  typedef typename T_grid_impl::iterator iterator;
  typedef typename T_grid_impl::const_iterator const_iterator;
  typedef typename T_grid_impl::T_location_request T_location_request;
  typedef typename T_grid_impl::T_location_response T_location_response;

protected:
  void make_blocks();

  /// The concrete grid object
  boost::shared_ptr<T_grid_impl> g_;

  /// Memory block for all data objects (absorbers)
  void* data_block_;

  /// One memory block for the densities of all cells
  array_2 rho_;
  /** One memory block for the intensities of all cells, indexed by
      (cell, wavelength).  */
  array_2 intensities_;

  void stupid (CCfits::ExtHDU& data_hdu,
	       const density_generator& gen,
	       int n_lambda);

public:
  /** This constructor doesn't do anything to the cell data. It is
      used by the arepo_grid, when the cell data is loaded by the
      full_sed_grid. */
  polychromatic_grid (boost::shared_ptr<T_grid_impl> g);

  /** Constructor loads cell data from a FITS file.  The supplied grid
      object should already have the structure set up. This is only
      used for the adaptive_grid. */
  polychromatic_grid (boost::shared_ptr<T_grid_impl> g,
		      CCfits::ExtHDU& data_hdu,
		      const density_generator& gen,
		      int n_lambda);
		      
  virtual ~polychromatic_grid ();

  /// Returns a reference to the grid intensity array.
  const array_2& intensities() const {return intensities_;};
  void reset() {intensities_=0;};
  /** This call signals that the intensities are not needed anymore
      and can be freed.  The individual cells have their intensity
      members reset to zero-length arrays. */
  void free_intensities() {
    intensities_.free();
    for (iterator c = begin (), e=end(); c != e; ++c) 
      c->data()->get_absorber().set_intensity(array_1());
  };

  /// \name Forwarding functions for the grid interface.
  ///@{
  T_location_response 
  location_request(const T_location_request& r) const {
    return g_->location_request(r); };
  void initialize_tracker(const typename T_cell_tracker::T_code& code, 
			  const vec3d& pos,
			  T_cell_tracker& c) const {
    g_->initialize_tracker(code, pos, c); };
  T_cell_tracker locate (const vec3d &p, int thread,
			 bool accept_outside=false) {
    return g_->locate (p, thread, accept_outside);};
  std::pair<T_cell_tracker, T_float> intersection_from_without (const ray_base& ray,
								int thread) {
    return g_->intersection_from_without (ray, thread);};
  int get_cell_number(const T_cell_tracker& c) const {
    return g_->get_cell_number(c); };
  int n_cells() const { return g_->n_cells(); };
  std::vector<bool> get_structure () const {return g_->get_structure();};
  bool in_grid(const vec3d& p) const { return g_->in_grid(p); };
  void assert_in_grid(const vec3d& p) const {  g_->assert_in_grid(p); };
  std::vector<bool> position_ownership(std::vector<vec3d>& pos) const {
    return g_->position_ownership(pos); };
  bool shared_domain() const { return g_->shared_domain(); };

  const vec3d& getmin() const {return g_->getmin();};
  const vec3d& getmax() const {return g_->getmax();};

  const_iterator begin () const {return g_->begin ();};
  iterator begin () {return g_->begin ();};
  const_iterator end () const {return g_->end ();};
  iterator end () {return g_->end ();};
  ///@}
};

#endif

  
